﻿using Kimd.Common;
using Kimd.Communication;
using Kimd.Motion;
using Kimd.Vision;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using static log4net.Appender.RollingFileAppender;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace Kimd.Logic
{
    public abstract class FlowBase
    {
        private Thread _flowThread;
        protected FlowManager _flowManager;
        protected bool _ctFlag;
        protected Stopwatch _ctCounter;
        protected Stopwatch _ctMove;
        public bool isSimulate = false;
        public string Description { get; set; }
        public FlowMode WorkMode { get; set; }
        public SpeedType WorkSpeed { get; set; }

        [XmlIgnore]
        public FlowStatus Status { get; set; } = new FlowStatus();
        public FlowBase(string flowName)
        {
            this.Description = flowName;
            this._ctCounter = new Stopwatch();
            this._ctMove = new Stopwatch();
            this._ctFlag = true;
            this.Status.IsEnabled = true;
        }
        public FlowBase(string flowName, FlowManager flowmanager)
            : this(flowName)
        {
            _flowThread = new Thread(flowMethod);
            _flowThread.IsBackground = true;
            _flowThread.Name = Description;
            this._flowManager = flowmanager;
        }
        /// <summary>
        /// 只在初始化是调用一次
        /// </summary>
        public void Open()
        {
            _flowThread.Start();
        }
        /// <summary>
        /// 只在系统关闭是调用
        /// </summary>
        public void Close()
        {
            _flowThread.Abort();
        }
        public bool CheckFlowCondition()
        {
            WaitForStart();
            if (IsBreak())
            {
                return false;
            }
            return true;
        }

        public void WaitForStart()
        {
            if (_flowManager.PauseFlag)
                Status.IsPaused = true;
            this._flowManager.WaitForStart();
        }
        public bool WaitForSignal(string fromFlowName, string signalName)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"等待来自流程[{fromFlowName}]的信号:[{signalName}]", this.Description, 0, "系统"));
            //卡住等待信号，两种情况会继续：1.收到信号 2.强制跳过
            bool result = this._flowManager.WaitForSignal(fromFlowName, signalName);
            if (result)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"收到来自流程[{fromFlowName}]的信号:[{signalName}]", this.Description, 0, "系统"));
            return result;
        }
        public bool CheckSignal(string fromFlowName, string signalName)
        {
            bool result = this._flowManager.GetSignal(fromFlowName, signalName).GetStatus();
            //if (result)
            //    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"收到来自流程[{fromFlowName}]的信号:[{signalName}]", this.Description, 0, "系统"));
            return result;
        }
        public void RegisterDirectSignal(string signalName, bool initState = false)
        {
            this._flowManager.RegisterSignal(Description, signalName, initState);
        }
        public void RegisterSwitchSignal(string signalName, bool initState = false)
        {
            this._flowManager.RegisterSwitchSignal(Description, signalName, initState);
        }
        public SignalBase GetSignal(string flowName, string signalName)
        {
            return this._flowManager.GetSignal(flowName, signalName);
        }
        public void SetSignal(string signalName)
        {
            this._flowManager.SetSignal(Description, signalName);
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"流程[{this.Description}]给出信号[{signalName}]", this.Description, 0, "系统"));
        }
        public void SetSignal(string flowName, string signalName)
        {
            this._flowManager.SetSignal(flowName, signalName);
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"流程[{flowName}]给出信号[{signalName}]", this.Description, 0, "系统"));
        }
        public void ResetSignal(string signalName)
        {
            this._flowManager.ResetSignal(Description, signalName);
        }
        /// <summary>
        /// 首次运行时进行的初始化动作
        /// </summary>
        public virtual void Init(out string errInfo)
        {
            errInfo = "";
            Status.IsStopped = false;
            Status.IsPaused = false;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, "Init...", this.Description, 0, "系统"));
        }
        /// <summary>
        /// 启动前准备
        /// </summary>
        /// <returns></returns>
        public virtual bool PreStartCheck()
        {
            return true;
        }
        /// <summary>
        /// 暂停或停止是调用
        /// </summary>
        public virtual void OnStop()
        {

        }
        public virtual void InSingleRunMode()
        {

        }
        public bool IsBreak()
        {
            return _flowManager.IsBreak();
        }
        public virtual void Method()
        {

        }
        public virtual void Home()
        {

        }
        public virtual void Calibrate()
        {

        }
        public virtual void SpotCheck()
        {

        }
        public bool CTCalculateNode(out double seconds)
        {
            seconds = 0;
            //并非首次运行，可以计算CT
            if (!this._ctFlag)
            {
                this._ctCounter.Stop();
                long miliSeconds = this._ctCounter.ElapsedMilliseconds;
                seconds = miliSeconds * 1.0 / 1000;
                this._ctCounter.Restart();
                return true;
            }
            else
            {
                this._ctFlag = false;
                this._ctCounter.Start();
                return false;
            }
        }
        public void CTStartCalculateNode()
        {
            this._ctCounter.Restart();
        }
        public void CTEndCalculateNode(out double seconds)
        {
            this._ctCounter.Stop();
            long miliSeconds = this._ctCounter.ElapsedMilliseconds;
            seconds = miliSeconds * 1.0 / 1000;
        }

        public void CTMoveStartCalculateNode()
        {
            this._ctMove.Restart();
        }

        public void CTMoveStopCalculateNode()
        {
            this._ctMove.Stop();
        }
        public void CTMoveEndCalculateNode(out double seconds)
        {
            this._ctMove.Stop();
            long miliSeconds = this._ctMove.ElapsedMilliseconds;
            seconds = miliSeconds * 1.0 / 1000;
        }
        public void ShowWarnAndPause(string errInfo, string moduleName, bool notAlarm = false)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(notAlarm ? MessageType.InfoAndPause : MessageType.Warn, errInfo, this.Description, 0, moduleName));
            //出错，停下所有线程
            _flowManager.Pause();
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
        }
        public void PauseFlow()
        {
            _flowManager.Pause();
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
        }
        public void checkTrayFullAndReplace(Tray tray, string errInfo, string module, bool isDryRun)
        {
            if (tray.Helper.IsFull)
            {
                if (!isDryRun)
                {
                    ShowWarnAndPause($"{module}:{errInfo}", module);
                    if (!CheckFlowCondition()) return;
                }
                tray.Helper.NewEmptyTray();
            }
        }
        public void WaitSensor(Sensor sensor, int timeOut, string errInfo, Action onErr = null, Action onResume = null)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"等待感应器 {sensor.Description} ON", this.Description, 0, sensor.Module));
            if (isSimulate)
                return;
            while (!sensor.WaitOn(timeOut) && !IsBreak())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, errInfo, this.Description, 1, sensor.Module));
                onErr?.Invoke();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                onResume?.Invoke();
                Thread.Sleep(20);
            }
        }
        public void WaitSensorOff(Sensor sensor, int timeOut, string errInfo, Action onErr = null, Action onResume = null)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"等待感应器 {sensor.Description} OFF", this.Description, 0, sensor.Module));
            if (isSimulate)
                return;
            while (!sensor.WaitOn(timeOut, false) && !IsBreak())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, errInfo, this.Description, 1, sensor.Module));
                onErr?.Invoke();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                onResume?.Invoke();
                Thread.Sleep(20);
            }
        }
        public void SingleCylinderOperate(Cylinder nozzle, int nozzleTimeOut, bool onoff, bool isNeedLog = false, string alias = "")
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"[{nozzle.Description}]设置[{onoff}] [{nozzle._bitNo1}]", this.Description, 0, nozzle.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak())
                return;
            if (onoff)
            {
                if (!nozzle.WaitOn(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle.Description}]到动点[{string.Join(",", nozzle.MoveNames)}]超时", this.Description, 1, nozzle.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                    //若为报错，需重新检测启动信号
                    WaitForStart();
                    if (!CheckFlowCondition()) return;
                    goto restart;
                }
            }
            else
            {
                if (!nozzle.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle.Description}]到原点[{string.Join(",", nozzle.OriginNames)}]超时", this.Description, 1, nozzle.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                    //若为报错，需重新检测启动信号
                    WaitForStart();
                    if (!CheckFlowCondition()) return;
                    goto restart;
                }
            }
#endif
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"单气缸操作 {nozzle.Description} {onoff}: {ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void SingleCylinderWait(Cylinder nozzle, int nozzleTimeOut, bool onoff)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"等待气缸 {nozzle.Description} {onoff}", this.Description, 0, nozzle.Module));
            if (isSimulate)
                return;
            restart:
            if (IsBreak())
                return;
            if (onoff)
            {
                if (!nozzle.InMove(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"等待 [{nozzle.Description}]到动点[{string.Join(",", nozzle.MoveNames)}]超时", this.Description, 1, nozzle.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                    //若为报错，需重新检测启动信号
                    WaitForStart();
                    if (!CheckFlowCondition()) return;
                    goto restart;
                }
            }
            else
            {
                if (!nozzle.InOrigin(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"等待 [{nozzle.Description}]到原点[{string.Join(",", nozzle.OriginNames)}]超时", this.Description, 1, nozzle.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                    //若为报错，需重新检测启动信号
                    WaitForStart();
                    if (!CheckFlowCondition()) return;
                    goto restart;
                }
            }
        }
        public void MultiCylinderOperate(List<Cylinder> nozzle, int nozzleTimeOut, List<bool> onoff, string alias = "", bool isNeedLog = false)
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多气缸操作 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} {onoff}", this.Description, 0, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            for (int i = 0; i < nozzle.Count; i++)
            {
                if (onoff[i])
                {
                    nozzle[i].On();
                }
                else
                {
                    nozzle[i].Off();
                }
            }
            for (int i = 0; i < nozzle.Count; i++)
            {
                if (onoff[i])
                {
                    if (!nozzle[i].WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle[i].Description}]到动点[{string.Join(",", nozzle[i].MoveNames)}]超时", this.Description, 1, nozzle[i].Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
                else
                {
                    if (!nozzle[i].WaitOff(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle[i].Description}]到原点[{string.Join(",", nozzle[i].OriginNames)}]超时", this.Description, 1, nozzle[i].Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多气缸操作 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} {onoff}: {ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void MultiCylinderWait(List<Cylinder> nozzle, int nozzleTimeOut, List<bool> onoff)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多气缸等待 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} {onoff}", this.Description, 3, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            for (int i = 0; i < nozzle.Count; i++)
            {
                if (onoff[i])
                {
                    if (!nozzle[i].InMove(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle[i].Description}]到动点[{string.Join(",", nozzle[i].MoveNames)}]超时", this.Description, 1, nozzle[i].Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
                else
                {
                    if (!nozzle[i].InOrigin(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"[{nozzle[i].Description}]到原点[{string.Join(",", nozzle[i].OriginNames)}]超时", this.Description, 1, nozzle[i].Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
        }
        public void SingleAxisChangeSpeed(Axis axis, double speed)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴变速 {axis.Description} 至 {speed}mm/s", this.Description, 3, axis.Module));
            axis.AxisChangeSpeed(speed);
        }
        public void SingleAxisMove2Point(Axis axis, string pointName, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false, double changePosition = 99999)
        {
            InSingleRunMode();
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴移动 {axis.Description} 至 {pointName}", this.Description, 3, axis.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak())
                return;
            string stopReason1 = "";
            if (isDefaultSpeed)
                axis.SetSpeed(WorkSpeed);
            else
                axis.SetSpeed(speedType);
            axis.Move2Point(pointName, out stopReason1, 1, true, changePosition);
            if (!string.IsNullOrEmpty(stopReason1))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1}", this.Description, 2, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
#endif
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"单轴移动 {axis.Description} 至 {pointName}: {ts.Milliseconds}ms", MessageLevel.CT);
            InSingleRunMode();
        }
        public void SingleAxisMove2PointSetSpeed(Axis axis, double position, double speed, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false)
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴移动 {axis.Description} 至 {position} speed:{speed}", this.Description, 2, axis.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            string stopReason1 = "";
            axis.MoveAbsoluteSetSpeed(position, speed, out stopReason1, 1);
            if (!string.IsNullOrEmpty(stopReason1))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1}", this.Description, 2, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"单轴移动 {axis.Description} 至 {position}: {ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void SingleAxisMove2Point(Axis axis, double position, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false)
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴移动 {axis.Description} 至 {position}", this.Description, 2, axis.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            string stopReason1 = "";
            if (isDefaultSpeed)
                axis.SetSpeed(WorkSpeed);
            else
                axis.SetSpeed(speedType);
            axis.MoveAbsolute(position, out stopReason1, 1);
            if (!string.IsNullOrEmpty(stopReason1))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1}", this.Description, 2, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"单轴移动 {axis.Description} 至 {position}: {ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void SingleAxisGoLimit(Axis axis, bool direction)
        {
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"{axis.Description}移动至极限", this.Description, 0, axis.Module));
            string stopReason1 = "";
            axis.SetSpeed(WorkSpeed);
            axis.MoveContinuous(direction, out stopReason1);
            if (!string.IsNullOrEmpty(stopReason1))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1}", this.Description, 3, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            if (direction)
            {
                while (!axis.PositiveLimit && !IsBreak())
                {
                    Thread.Sleep(2);
                }
                axis.Stop(false);
            }
            else
            {
                while (!axis.NegativeLimit && !IsBreak())
                {
                    Thread.Sleep(2);
                }
                axis.Stop(false);
            }
        }
        public void SingleAxisGoHome(Axis axis, string alias = "")
        {
            DateTime startTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴回零 {axis.Description}", this.Description, 0, axis.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            axis.SetSpeed(SpeedType.Home);
            if (!axis.GoHome((short)axis.HomeMode, axis.HomeDirP))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{axis.Description} 回零超时!", this.Description, 4, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            if (!axis.Home)
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{axis.Description} 回零失败!", this.Description, 4, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"单轴回零 {axis.Description}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void AxisGoHomeSimultaneously(List<Axis> axis, string alias = "", bool isNeedLog = false)
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴回零 {string.Join(",", axis.Select(n => n.Description).ToArray())}", this.Description, 0, axis[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> axisNames = new List<string>();
            axis.ForEach(a => axisNames.Add(a.Description));
            if (axis != null && axis.Count > 0)
            {
                foreach (var singleaxis in axis)
                {
                    singleaxis.SetSpeed(SpeedType.Home);
                    singleaxis.GoHome((short)singleaxis.HomeMode, singleaxis.HomeDirP, false);
                }
                foreach (var singleaxis in axis)
                {
                    if (!singleaxis.WaitHome())
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{singleaxis.Description} 回零超时!", this.Description, 4, singleaxis.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
                bool success = true;
                Axis errAxis = null;
                foreach (var singleaxis in axis)
                {
                    if (!singleaxis.Home)
                    {
                        errAxis = singleaxis;
                        success = false;
                        break;
                    }
                }
                if (!success)
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{errAxis.Description} 回零失败!", this.Description, 4, errAxis.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                    //若为报错，需重新检测启动信号
                    WaitForStart();
                    if (!CheckFlowCondition()) return;
                    goto restart;
                }
            }

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多轴:{string.Join(",", axisNames)}回零:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void SingleAxisCheckPoint(Axis axis, string posName)
        {
        restart:
            if (IsBreak())
                return;
            if (!axis.MotionPosition.ContainsKey(posName))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{axis.Description}不存在名为{posName}的点位", axis.Description, 5, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
        }
        public void AxisMoveSimultaneously(Axis axis1, Axis axis2, string pointName, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", object lockObj = null)
        {
            InSingleRunMode();
            DateTime startTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴移动 {axis1},{axis2} 至 {pointName}", this.Description, 0, axis1.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"两轴:{axis1.Description},{axis2.Description}运动至{pointName}", this.Description, 0, axis1.Module));
            string stopReason1 = "";
            string stopReason2 = "";
            if (isDefaultSpeed)
            {
                axis1.SetSpeed(WorkSpeed);
                axis2.SetSpeed(WorkSpeed);
            }
            else
            {
                axis1.SetSpeed(speedType);
                axis2.SetSpeed(speedType);
            }
            axis1.Move2Point(pointName, out stopReason1, 1, false);
            axis2.Move2Point(pointName, out stopReason2, 1, false);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if(lockObj != null)
                Monitor.Exit(lockObj);
            axis1.Wait2Point(pointName, 1, out stopReason1);
            axis2.Wait2Point(pointName, 1, out stopReason2);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
#endif

            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"两轴:{axis1.Description},{axis2.Description}运动至{pointName}:{ts.Milliseconds}ms", MessageLevel.CT);
            InSingleRunMode();
        }
        public void AxisMoveSimultaneously(Axis axis1, Axis axis2, Axis axis3, string pointName, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false, object lockObj = null)
        {
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"三轴:{axis1.Description},{axis2.Description},{axis3.Description}运动至{pointName}", this.Description, 0, axis1.Module));
            DateTime startTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            string stopReason1 = "";
            string stopReason2 = "";
            string stopReason3 = "";
            if (isDefaultSpeed)
            {
                axis1.SetSpeed(WorkSpeed);
                axis2.SetSpeed(WorkSpeed);
                axis3.SetSpeed(WorkSpeed);
            }
            else
            {
                axis1.SetSpeed(speedType);
                axis2.SetSpeed(speedType);
                axis3.SetSpeed(speedType);
            }
            axis1.Move2Point(pointName, out stopReason1, 1, false);
            axis2.Move2Point(pointName, out stopReason2, 1, false);
            axis3.Move2Point(pointName, out stopReason3, 1, false);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if (lockObj != null)
                Monitor.Exit(lockObj);
            axis1.Wait2Point(pointName, 1, out stopReason1);
            axis2.Wait2Point(pointName, 1, out stopReason2);
            axis3.Wait2Point(pointName, 1, out stopReason3);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"三轴:{axis1.Description},{axis2.Description},{axis3.Description}运动至{pointName}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void AxisMoveSimultaneously(Axis axis1, Axis axis2, double pos1, double pos2, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", object lockObj = null)
        {
            DateTime startTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴移动 {axis1},{axis2} 至 {pos1},{pos2}", this.Description, 0, axis1.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"三轴:{axis1.Description},{axis2.Description}运动至{pos1},{pos2}", this.Description, 0, axis1.Module));
            string stopReason1 = "";
            string stopReason2 = "";
            string stopReason3 = "";
            if (isDefaultSpeed)
            {
                axis1.SetSpeed(WorkSpeed);
                axis2.SetSpeed(WorkSpeed);
            }
            else
            {
                axis1.SetSpeed(speedType);
                axis2.SetSpeed(speedType);
            }
            axis1.MoveAbsolute(pos1, out stopReason1, 1, false);
            axis2.MoveAbsolute(pos2, out stopReason2, 1, false);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if (lockObj != null)
                Monitor.Exit(lockObj);
            axis1.WaitAxisInPosition(pos1, 1, out stopReason1);
            axis2.WaitAxisInPosition(pos2, 1, out stopReason2);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多轴移动 {axis1},{axis2} 至 {pos1},{pos2}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void AxisMoveSimultaneously(Axis axis1, Axis axis2, Axis axis3, double pos1, double pos2, double pos3, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", object lockObj = null)
        {
            DateTime startTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴移动 {axis1},{axis2},{axis3} 至 {pos1},{pos2},{pos3}", this.Description, 0, axis1.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"三轴:{axis1.Description},{axis2.Description},{axis3.Description}运动至{pos1},{pos2},{pos3}", this.Description, 0, axis1.Module));
            string stopReason1 = "";
            string stopReason2 = "";
            string stopReason3 = "";
            if (isDefaultSpeed)
            {
                axis1.SetSpeed(WorkSpeed);
                axis2.SetSpeed(WorkSpeed);
                axis3.SetSpeed(WorkSpeed);
            }
            else
            {
                axis1.SetSpeed(speedType);
                axis2.SetSpeed(speedType);
                axis3.SetSpeed(speedType);
            }
            axis1.MoveAbsolute(pos1, out stopReason1, 1, false);
            axis2.MoveAbsolute(pos2, out stopReason2, 1, false);
            axis3.MoveAbsolute(pos3, out stopReason3, 1, false);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if (lockObj != null)
                Monitor.Exit(lockObj);
            axis1.WaitAxisInPosition(pos1, 1, out stopReason1);
            axis2.WaitAxisInPosition(pos2, 1, out stopReason2);
            axis3.WaitAxisInPosition(pos3, 1, out stopReason3);
            if (!string.IsNullOrEmpty(stopReason1) || !string.IsNullOrEmpty(stopReason2) || !string.IsNullOrEmpty(stopReason3))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1},{stopReason2},{stopReason3}", this.Description, 5, axis1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"三轴:{axis1.Description},{axis2.Description},{axis3.Description}运动至{pos1},{pos2},{pos3}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void AxisMoveSimultaneously(List<Axis> allAxis, string pointName, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false, object lockObj = null)
        {
            InSingleRunMode();
            DateTime startTime = DateTime.Now;
            List<string> names = allAxis.Select(n => n.Description).ToList();
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴移动 {string.Join(",", allAxis.Select(n => n.Description).ToArray())} 至 {pointName}", this.Description, 0, allAxis[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak())
                return;
            List<string> stopReasons = new List<string>();
            allAxis.ForEach(a =>
            {
                a.SetSpeed(isDefaultSpeed ? WorkSpeed : speedType);
                a.Move2Point(pointName, out string stopReason, 1, false);
                stopReasons.Add(stopReason);
            });
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, allAxis[0].Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if (lockObj != null)
                Monitor.Exit(lockObj);
            stopReasons = new List<string>();
            allAxis.ForEach(a =>
            {
                a.Wait2Point(pointName, 1, out string stopReason);
                stopReasons.Add(stopReason);
            });
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, allAxis[0].Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
#endif
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多轴:{string.Join(",", allAxis)} 运动至{pointName}:{ts.Milliseconds}ms", MessageLevel.CT);
            InSingleRunMode();
        }
        public void AxisMoveSimultaneously(List<Axis> allAxis, List<double> positions, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "", bool isNeedLog = false, object lockObj = null)
        {
            InSingleRunMode();
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴移动 {string.Join(",", allAxis.Select(n => n.Description).ToArray())} 至 {string.Join(",", positions)}", this.Description, 0, allAxis[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak()) return;
            List<string> stopReasons = new List<string>();
            allAxis.Zip(positions, (axis, p) => new { axis = axis, p = p })
                   .ToList()
                   .ForEach(item =>
                   {
                       item.axis.SetSpeed(isDefaultSpeed ? WorkSpeed : speedType);
                       item.axis.MoveAbsolute(item.p, out string stopReason, 1, false);
                       stopReasons.Add(stopReason);
                   });
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, allAxis[0].Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            //成功动起来以后，才能释放锁
            if (lockObj != null)
                Monitor.Exit(lockObj);
            stopReasons = new List<string>();
            allAxis.Zip(positions, (axis, p) => new { axis = axis, p = p })
                   .ToList()
                   .ForEach(item =>
                   {
                       item.axis.WaitAxisInPosition(item.p, 1, out string stopReason);
                       stopReasons.Add(stopReason);
                   });
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, allAxis[0].Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
#endif
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多轴移动 {string.Join(",", allAxis.Select(n => n.Description).ToArray())} 至 {string.Join(",", positions)}:{ts.Milliseconds}ms", MessageLevel.CT);
            InSingleRunMode();
        }
        public void SingleAxisMoveContinuous(Axis axis, bool direction, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, bool isNeedLog = false)
        {
            DateTime startTime = DateTime.Now;
            if (isNeedLog)
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"单轴连续运动，方向：{direction}", this.Description, 3, axis.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
#if DEBUGWITHOUTMACHINE
            Thread.Sleep(500);
#else
        restart:
            if (IsBreak())
                return;
            string stopReason1 = "";
            if (isDefaultSpeed)
                axis.SetSpeed(WorkSpeed);
            else
                axis.SetSpeed(speedType);
            axis.MoveContinuous(direction, out stopReason1);
            if (!string.IsNullOrEmpty(stopReason1))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{stopReason1}", this.Description, 2, axis.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
#endif
        }
        public void CoordinateMoveSimultaneously(Coordinate2D crd1, Coordinate2D crd2, List<double> positions1, List<double> positions2, bool isDefaultSpeed = true, SpeedType speedType = SpeedType.Work, string alias = "")
        {
            DateTime startTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴插补 {crd1.Description} 至 {string.Join(",", positions1)}", this.Description, 0, crd1.Module));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多轴插补 {crd1.Description} 至 {string.Join(",", positions2)}", this.Description, 0, crd2.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak()) return;
            List<string> stopReasons = new List<string>();
            crd1.MoveLine(positions1.ToArray(), out string stopReason1, 1, false);
            stopReasons.Add(stopReason1);
            crd2.MoveLine(positions2.ToArray(), out string stopReason2, 1, false);
            stopReasons.Add(stopReason2);
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, crd1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            stopReasons = new List<string>();
            crd1.WaitCrdInPosition(positions1.ToArray(), 1, out stopReason1);
            stopReasons.Add(stopReason1);
            crd2.WaitCrdInPosition(positions2.ToArray(), 1, out stopReason2);
            stopReasons.Add(stopReason2);
            if (stopReasons.Any(s => !string.IsNullOrEmpty(s)))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{string.Join(",", stopReasons)}", this.Description, 5, crd1.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            TimeSpan ts = DateTime.Now - startTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多轴插补 {crd1.Description} 至 {string.Join(",", positions1)}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzleGetProduct(Cylinder nozzle, Cylinder vac, Sensor vacSensor, int nozzleTimeOut = 5000, int delayAfterOpenVac = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false, string alias = "")
        {
            DateTime dateTime = DateTime.Now;

            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴取料 {nozzle.Description}", this.Description, 0, nozzle.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}取料", this.Description, 0, nozzle.Module));
            if (nozzle != null && !nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;

            DateTime nozzleDownTime = DateTime.Now;
            //开真空
            vac.On();
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);

            DateTime delayAfterOpenVacTime = DateTime.Now;
            //若感应到真空，说明有产品
            if (!isDryRun && !vacSensor.WaitOn())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vacSensor.Description}未感应到产品,请检查是否有产品", this.Description, 6, vacSensor.Module));
                //抬起吸嘴
                nozzle.Off();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;

            DateTime vacSenseTime = DateTime.Now;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);

            DateTime beforeNozzleUpTime = DateTime.Now;

            if (nozzle != null && !nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayBeforeVacCheck);

            DateTime vacCheckTime = DateTime.Now;
            //抬起后未感应到真空
            if (!isDryRun && !vacSensor.WaitOn())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vacSensor.Description}未感应到,吸嘴{nozzle.Description}吸料失败!", this.Description, 6, vacSensor.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }

            //TimeSpan ts = DateTime.Now - dateTime;
            //if (!string.IsNullOrEmpty(alias))
            //    LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            //else
            //    LogHelper.Instance.Log(this.Description, $"吸嘴取料 {nozzle.Description}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzleGetProduct(Cylinder nozzle, Cylinder headVac, Cylinder tailVac, Sensor headVacSensor, Sensor tailVacSensor, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterOpenVac = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false, string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}取料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayAfterNozzleDown);
            //开真空
            headVac.On();
            tailVac.On();
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);
            //若感应到真空，说明有产品
            if (!isDryRun && (!headVacSensor.WaitOn() || !tailVacSensor.WaitOn()))
            {
                if (!headVacSensor.WaitOn())
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{headVacSensor.Description}未感应到产品,请检查是否有产品", this.Description, 6, headVacSensor.Module));
                if (!tailVacSensor.WaitOn())
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{tailVacSensor.Description}未感应到产品,请检查是否有产品", this.Description, 6, tailVacSensor.Module));
                //抬起吸嘴
                nozzle.Off();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayBeforeVacCheck);
            //抬起后未感应到真空
            if (!isDryRun && (!headVacSensor.WaitOn() || tailVacSensor.WaitOn()))
            {
                if (!headVacSensor.WaitOn())
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{headVacSensor.Description}未感应到,吸嘴{nozzle.Description}吸料失败!", this.Description, 6, headVacSensor.Module));
                if (!tailVacSensor.WaitOn())
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{tailVacSensor.Description}未感应到,吸嘴{nozzle.Description}吸料失败!", this.Description, 6, tailVacSensor.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"吸嘴取料 {nozzle.Description}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProduct(Cylinder nozzle, Cylinder vac, Cylinder revVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, string alias = "")
        {
            DateTime dateTime = DateTime.Now;

            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴放料 {nozzle.Description}", this.Description, 0, nozzle.Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}放料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            vac.Off();
            //开破真空
            revVac.On();
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //关破真空
            revVac.Off();
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"吸嘴放料 {nozzle.Description}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProduct(Cylinder nozzle, Cylinder vacHead, Cylinder vacTail, Cylinder headRevVac, Cylinder tailRevVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, string alias = "")
        {
            DateTime dateTime = DateTime.Now;

            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}放料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            vacHead.Off();
            vacTail.Off();
            //开破真空
            headRevVac.On();
            tailRevVac.On();
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //关破真空
            headRevVac.Off();
            tailRevVac.Off();
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"吸嘴放料 {nozzle.Description}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzleGetProduct(List<Cylinder> nozzle, List<Cylinder> vac, List<Sensor> vacSensor, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterOpenVac = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false, List<bool> productStatus = null, string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴取料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}", this.Description, 0, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}取料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayAfterNozzleDown);
            //开真空
            if (productStatus != null)
            {
                index = 0;
                foreach (var v in vac)
                {
                    if (productStatus[index])
                        v.On();
                    index++;
                }
            }
            else
            {
                foreach (var v in vac)
                {
                    v.On();
                }
            }
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in vacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;

            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzleGetProductHeadTail(List<Cylinder> nozzle, List<Cylinder> headVac, List<Cylinder> tailVac, List<Sensor> headVacSensor, List<Sensor> tailVacSensor, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterOpenVac = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false, List<bool> productStatus = null, string alias = "")
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴头尾取料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}", this.Description, 0, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}取料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayAfterNozzleDown);
            //开真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        headVac[i].On();
                        tailVac[i].On();
                    }
                }
            }
            else
            {
                for (int i = 0; i < headVac.Count; i++)
                {
                    headVac[i].On();
                    tailVac[i].On();
                }
            }
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in headVacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                    index = 0;
                    foreach (var vs in tailVacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in headVacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    foreach (var vs in tailVacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;

            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in headVacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in tailVacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in headVacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    //抬起后未感应到真空
                    foreach (var vs in tailVacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
        }
        public void NozzlePutProduct(List<Cylinder> nozzle, List<Cylinder> vac, List<Cylinder> revVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, List<bool> productStatus = null, string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}", this.Description, 0, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in vac)
                {
                    if (productStatus[index])
                        rv.Off();
                    index++;
                }
            }
            else
            {
                //关真空
                foreach (var rv in vac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in revVac)
                {
                    if (productStatus[index])
                        rv.On();
                    index++;
                }
            }
            else
            {
                //开破真空
                foreach (var rv in revVac)
                {
                    rv.On();
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //关破真空
            foreach (var rv in revVac)
            {
                rv.Off();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProduct(List<Cylinder> nozzle, List<Cylinder> headVac, List<Cylinder> tailVac, List<Cylinder> headRevVac, List<Cylinder> tailRevVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, List<bool> productStatus = null, string alias = "")
        {
            DateTime dateTime = DateTime.Now;

            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}", this.Description, 0, nozzle[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        headVac[i].Off();
                        tailVac[i].Off();
                    }
                }
            }
            else
            {
                //关真空
                foreach (var rv in headVac)
                {
                    rv.Off();
                }
                foreach (var rv in tailVac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        headRevVac[i].On();
                        tailRevVac[i].On();
                    }
                }
            }
            else
            {
                //开破真空
                foreach (var rv in headRevVac)
                {
                    rv.On();
                }
                //开破真空
                foreach (var rv in tailRevVac)
                {
                    rv.On();
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //开破真空
            foreach (var rv in headRevVac)
            {
                rv.On();
            }
            //开破真空
            foreach (var rv in tailRevVac)
            {
                rv.On();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProduct(List<Axis> z, string position, string safePos, List<Cylinder> headVac, List<Cylinder> tailVac, List<Cylinder> headRevVac, List<Cylinder> tailRevVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, List<bool> productStatus = null, string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴放料 {string.Join(",", z.Select(n => n.Description).ToArray())}", this.Description, 0, z[0].Module));
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<Axis> nozzleNames = new List<Axis>();
            int jjj = 0;
            z.ForEach(a =>
            {
                if (productStatus[jjj])
                    nozzleNames.Add(a);
                jjj++;
            });
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, z[0].Module));
            AxisMoveSimultaneously(nozzleNames, position);
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        headVac[i].Off();
                        tailVac[i].Off();
                    }
                }
            }
            else
            {
                //关真空
                foreach (var rv in headVac)
                {
                    rv.Off();
                }
                foreach (var rv in tailVac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        headRevVac[i].On();
                        tailRevVac[i].On();
                    }
                }
            }
            else
            {
                //开破真空
                foreach (var rv in headRevVac)
                {
                    rv.On();
                }
                //开破真空
                foreach (var rv in tailRevVac)
                {
                    rv.On();
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            AxisMoveSimultaneously(z, safePos);
            if (!CheckFlowCondition()) return;
            //开破真空
            foreach (var rv in headRevVac)
            {
                rv.On();
            }
            //开破真空
            foreach (var rv in tailRevVac)
            {
                rv.On();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias}: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", z.Select(n => n.Description).ToArray())}:{ts.Milliseconds}ms", MessageLevel.CT);
        }
        public bool NozzleGrabProduct(Cylinder nozzle, Cylinder grab, Sensor hasProduct, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterGrabOn = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false)
        {
            if (IsBreak())
                return true;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}取料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return true;
                return false;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return true;
            Thread.Sleep(delayAfterNozzleDown);
            //夹爪关
            if (!grab.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{grab.Description}到动点{string.Join(",", grab.MoveNames)}超时", this.Description, 1, grab.Module));
                //抬起吸嘴
                nozzle.Off();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return true;
                return false;
            }
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterGrabOn);
            //若感应到真空，说明有产品
            if (!isDryRun && !hasProduct.WaitOn())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{hasProduct.Description} 未感应到产品,请检查是否有产品", this.Description, 6, hasProduct.Module));
                //
                grab.On();
                //抬起吸嘴
                nozzle.Off();
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return true;
                return false;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return true;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return true;
            System.Threading.Thread.Sleep(delayBeforeVacCheck);
            //抬起后未感应到真空
            if (!isDryRun && !hasProduct.WaitOn())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{hasProduct.Description}未感应到,吸嘴{nozzle.Description}取料失败!", this.Description, 6, hasProduct.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return true;
                return false;
            }
            return true;
        }
        public bool NozzleGrabProductSimple(Cylinder nozzle, Cylinder grab, Sensor hasProduct, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterGrabOn = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}取料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                return false;
            }
            Thread.Sleep(delayAfterNozzleDown);
            //夹爪关
            if (!grab.WaitOff(nozzleTimeOut))
            {
                return false;
            }
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterGrabOn);
            //若感应到真空，说明有产品
            if (!isDryRun && !hasProduct.WaitOn())
            {
                return false;
            }
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
            }
            //抬起后未感应到真空
            if (!isDryRun && !hasProduct.WaitOn())
            {
                return false;
            }
            return true;
        }
        public bool NozzleGetProductSimple(Cylinder nozzle, Cylinder vac, Sensor hasProduct, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterGrabOn = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}取料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                nozzle.Off();
                return false;
            }
            Thread.Sleep(delayAfterNozzleDown);
            //夹爪关
            vac.On();
            if (!hasProduct.WaitOn(5000))
            {
                nozzle.Off();
                return false;
            }
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                nozzle.Off();
                return false;
            }
            System.Threading.Thread.Sleep(delayBeforeVacCheck);
            //抬起后未感应到真空
            if (!isDryRun && !hasProduct.WaitOn())
            {
                return false;
            }
            return true;
        }
        public void NozzleGrabProduct(List<Cylinder> nozzle, List<Cylinder> grab, List<Sensor> hasProduct, int nozzleTimeOut = 5000, int delayAfterNozzleDown = 0, int delayAfterOpenVac = 0, int delayBeforeNozzleUp = 0, int delayBeforeVacCheck = 0, bool isDryRun = false, List<bool> productStatus = null)
        {
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}取料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            Thread.Sleep(delayAfterNozzleDown);
            //同时关夹爪
            if (productStatus != null)
            {
                index = 0;
                foreach (var v in grab)
                {
                    if (productStatus[index])
                        v.Off();
                    index++;
                }
            }
            else
            {
                foreach (var v in grab)
                {
                    v.Off();
                }
            }
            // 等待夹爪打开
            if (productStatus != null)
            {
                index = 0;
                foreach (var v in grab)
                {
                    if (productStatus[index])
                    {
                        SingleCylinderOperate(v, 5000, false);
                    }
                    index++;
                }
            }
            else
            {
                foreach (var v in grab)
                {
                    SingleCylinderOperate(v, 5000, false);
                }
            }
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in hasProduct)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in hasProduct)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;

            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in hasProduct)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in hasProduct)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
        }
        public void NozzleReleaseProduct(Cylinder nozzle, Cylinder grab, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0)
        {
        restart:
            if (IsBreak())
                return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}放料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到动点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);

            if (!grab.WaitOn(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{grab.Description}到原点{string.Join(",", grab.MoveNames)}超时", this.Description, 1, grab.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozzle.Description}到原点{string.Join(",", nozzle.MoveNames)}超时", this.Description, 1, nozzle.Module));
                //出错，停下所有线程
                _flowManager.Pause();
            }
            //if(hasProduct.WaitOn())
            //{
            //    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{hasProduct.Description} 感应到，料未成功放下", this.Description, 0, grab.Module));
            //    //出错，停下所有线程
            //    _flowManager.Pause();
            //    //若为报错，需重新检测启动信号
            //    WaitForStart();
            //    if (!CheckFlowCondition()) return;
            //    goto restart;
            //}
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
        }
        public bool NozzlePutProductSimple(Cylinder nozzle, Cylinder vac, Cylinder revVac, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0)
        {
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"吸嘴:{nozzle.Description}放料", this.Description, 0, nozzle.Module));
            if (!nozzle.WaitOn(nozzleTimeOut))
            {
                nozzle.Off();
                return false;
            }
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);

            vac.Off();
            revVac.On();
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            if (!nozzle.WaitOff(nozzleTimeOut))
            {
                return false;
            }
            revVac.Off();
            return true;
        }
        public void NozzleReleaseProduct(List<Cylinder> nozzle, List<Cylinder> grab, int nozzleTimeOut = 5000, int delayBeforeCloseVac = 0, int delayBeforeNozzleUp = 0, List<bool> productStatus = null)
        {
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空前延时
            System.Threading.Thread.Sleep(delayBeforeCloseVac);
            //关真空
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in grab)
                {
                    if (productStatus[index])
                    {
                        rv.On();
                    }
                    index++;
                }
            }
            else
            {
                //关真空
                foreach (var rv in grab)
                {
                    rv.On();
                }
            }
            //关真空
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in grab)
                {
                    if (productStatus[index])
                    {
                        SingleCylinderOperate(rv, 5000, true);
                    }
                    index++;
                }
            }
            else
            {
                //关真空
                foreach (var rv in grab)
                {
                    SingleCylinderOperate(rv, 5000, true);
                }
            }

            WaitForStart();
            if (!CheckFlowCondition()) return;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;
        }
        public bool ReadPLC(PLCOperator plc, RegisterType registerType, int address, out int val)
        {
            val = 0;
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            bool isSuccess = plc.Read(registerType, DataType.Short, address, 1, out vals, out errCode);
            if (isSuccess)
            {
                val = Convert.ToInt16(vals[0]);
            }
            return isSuccess;
        }
        public bool ReadPLC(PLCOperator plc, RegisterType registerType, int address, int length, out short[] val)
        {
            val = null;
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            bool isSuccess = plc.Read(registerType, DataType.Short, address, length, out vals, out errCode);
            if (isSuccess)
            {
                val = vals.Select(v => Convert.ToInt16(v)).ToArray();
            }
            return isSuccess;
        }
        public void ReadPLC(PLCOperator plc, int address, out bool status)
        {
        restart:
            status = false;
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            bool isSuccess = plc.Read(RegisterType.MW, DataType.Bool, address, 1, out vals, out errCode);
            if (isSuccess)
            {
                status = vals[0].Equals("1");
            }
            else
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"读取PLC地址{address}失败,错误代码:{errCode}", this.Description, 7, plc.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
        }
        public void WritePLC(PLCOperator plc, int address, bool status)
        {
        restart:
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            if (status)
                vals.Add("1");
            else
                vals.Add("0");
            bool isSuccess = plc.Write(RegisterType.MW, DataType.Bool, address, vals, out errCode);
            if (!isSuccess)
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"写入PLC地址{address}失败,错误代码:{errCode}", this.Description, 7, plc.Module));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
        }
        public bool ReadPLC(PLCOperator plc, RegisterType readType, int address, int length, out bool[] status)
        {
            status = new bool[length];
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            bool isSuccess = plc.Read(readType, DataType.Bool, address, length, out vals, out errCode);
            if (isSuccess)
            {
                for (int i = 0; i < status.Length; i++)
                {
                    status[i] = vals[i].Equals("1");
                }
            }
            //else
            //{
            //    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"读取PLC地址{address}失败,错误代码:{errCode}", this.Description, 0, plc.Module));
            //    //出错，停下所有线程
            //    _flowManager.Pause();
            //    //若为报错，需重新检测启动信号
            //    WaitForStart();
            //    if (!CheckFlowCondition()) return;
            //    goto restart;
            //}
            return isSuccess;
        }
        public bool WriteLC(PLCOperator plc, RegisterType registerType, int address, int length, bool[] status)
        {
        restart:
            //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"读取PLC地址:{address}", this.Description, 0, "系统"));
            int errCode = 0;
            List<string> vals = new List<string>();
            for (int i = 0; i < status.Length; i++)
            {
                if (status[i])
                    vals.Add("1");
                else
                    vals.Add("0");
            }
            bool isSuccess = plc.Write(registerType, DataType.Bool, address, vals, out errCode);
            //if (!isSuccess)
            //{
            //    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"写入PLC地址{address}失败,错误代码:{errCode}", this.Description, 0, plc.Module));
            //    //出错，停下所有线程
            //    _flowManager.Pause();
            //    //若为报错，需重新检测启动信号
            //    WaitForStart();
            //    if (!CheckFlowCondition()) return;
            //    goto restart;
            //}
            return isSuccess;
        }
        public void TcpClientSend(CommunicationHelper helper, SendPackage sendPackage)
        {
        restart:
            if (IsBreak()) return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"向Tcp客户端{helper.Description}发送:{sendPackage.Message}", this.Description, 0, "系统"));
            if (!helper.Connect())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{helper.Description}连接服务器失败", this.Description, 8, "系统"));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto restart;
            }
            helper.Send(sendPackage);
        }
        public void TcpClientWait(CommunicationHelper helper, SendPackage sendPackage, int timeOut, out string recvStr)
        {
        rewait:
            recvStr = string.Empty;
            DateTime startTime = DateTime.Now;
            TimeSpan ts = DateTime.Now - startTime;
            while (!sendPackage.SendFlag && !IsBreak() && ts.TotalMilliseconds < timeOut)
            {
                //暂停时不计时
                bool isEnterPause = false;
                while (_flowManager.PauseFlag && !IsBreak())
                {
                    isEnterPause = true;
                    Thread.Sleep(20);
                }
                if (isEnterPause)
                {
                    isEnterPause = false;
                    startTime = DateTime.Now;
                }

                ts = DateTime.Now - startTime;
                Thread.Sleep(10);
            }
            if (!CheckFlowCondition()) return;
            if (ts.TotalMilliseconds >= timeOut)
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{helper.Description}接收超时", this.Description, 8, "系统"));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto rewait;
            }
            if (sendPackage.SendFlag)
            {
                sendPackage.SendFlag = false;
                recvStr = sendPackage.RecvStr;
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"收到Tcp客户端{helper.Description}回复:{recvStr}", this.Description, 0, "系统"));
            }
        }
        public void TcpClientSendAndReceive(CommunicationHelper helper, SendPackage sendPackage, int timeOut, int retryTimes, out string recvStr)
        {

        resend:
            helper.ClearPackage();
            recvStr = "";
            if (IsBreak()) return;
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"向Tcp客户端{helper.Description}发送:{sendPackage.Message}", this.Description, 0, "系统"));
            if (!helper.Connect())
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{helper.Description}连接服务器失败", this.Description, 8, "系统"));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto resend;
            }
            int hs = sendPackage.GetHashCode();
            //helper.EmptySendBuffer();
            helper.Send(sendPackage);

            DateTime startTime = DateTime.Now;
            TimeSpan ts = DateTime.Now - startTime;
            while (!sendPackage.SendFlag && !IsBreak() && ts.TotalMilliseconds < timeOut)
            {
                ts = DateTime.Now - startTime;
                Thread.Sleep(10);
            }
            if (ts.TotalMilliseconds >= timeOut)
            {
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{helper.Description}接收超时", this.Description, 8, "系统"));
                //出错，停下所有线程
                _flowManager.Pause();
                //若为报错，需重新检测启动信号
                WaitForStart();
                if (!CheckFlowCondition()) return;
                goto resend;
            }
            if (sendPackage.SendFlag)
            {
                sendPackage.SendFlag = false;
                recvStr = sendPackage.RecvStr;
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"收到Tcp客户端{helper.Description}回复:{recvStr}", this.Description, 0, "系统"));
            }
        }
        private void flowMethod()
        {
            while (true)
            {
                if (Status.IsEnabled)
                {
                    if (Status.IsBackground)
                    {
                        Status.IsHomeFinish = true;
                        Status.IsStopped = true;
                        //执行用户逻辑
                        Method();
                        Thread.Sleep(100);
                    }
                    else
                    {
                        if (WorkMode == FlowMode.Home && !Status.IsHomeFinish)
                        {
                            if (!_flowManager.IsBreak())
                            {
                                //初始进入暂停状态，等待启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                //执行用户逻辑
                                Home();
                                if (!_flowManager.IsBreak())
                                {
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"{this.Description} 回零完成", this.Description, 0, "系统"));
                                    Status.IsHomeFinish = true;
                                    Status.IsStopped = true;
                                }
                            }
                            else
                            {
                                if (!Status.IsStopped)
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, "用户停止", this.Description, 0, "系统"));
                                Status.IsStopped = true;
                            }
                        }
                        else if (WorkMode == FlowMode.Calibrate && !Status.IsCalibrateFinish)
                        {
                            if (!_flowManager.IsBreak())
                            {
                                //初始进入暂停状态，等待启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                //执行用户逻辑
                                Calibrate();
                                if (!_flowManager.IsBreak())
                                {
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"{this.Description} 标定完成", this.Description, 0, "系统"));
                                    Status.IsCalibrateFinish = true;
                                    Status.IsStopped = true;
                                }
                            }
                            else
                            {
                                if (!Status.IsStopped)
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, "用户停止", this.Description, 0, "系统"));
                                Status.IsStopped = true;
                            }
                        }
                        else if (WorkMode == FlowMode.SpotCheck && !Status.IsSpotCheckFinish)
                        {
                            if (!_flowManager.IsBreak())
                            {
                                //初始进入暂停状态，等待启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                //执行用户逻辑
                                SpotCheck();
                                if (!_flowManager.IsBreak())
                                {
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"{this.Description} 点检完成", this.Description, 0, "系统"));
                                    Status.IsSpotCheckFinish = true;
                                    Status.IsStopped = true;
                                }
                            }
                            else
                            {
                                if (!Status.IsStopped)
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, "用户停止", this.Description, 0, "系统"));
                                Status.IsStopped = true;
                            }
                        }
                        else if (WorkMode == FlowMode.Auto)
                        {
                            if (!_flowManager.IsBreak())
                            {
                                //初始进入暂停状态，等待启动信号
                                WaitForStart();
                                //执行用户逻辑
                                Method();
                            }
                            else
                            {
                                if (!Status.IsStopped)
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, "用户停止", this.Description, 0, "系统"));
                                Status.IsStopped = true;
                            }
                        }
                    }
                }
                Thread.Sleep(20);
            }
        }
        public void NozzleGetProductExt(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Sensor> vacSensor,
                                        List<Cylinder> vacOther,
                                        List<Cylinder> revVacOther,
                                        string zGetPos,
                                        string zSafePos,
                                        string localName,
                                        int nozzleTimeOut = 5000,
                                        int delayAfterOpenVac = 0,
                                        int delayBeforeVacCheck = 0,
                                        bool isDryRun = false,
                                        List<bool> productStatus = null,
                                        string alias = "")
        {
            int index = 0;
            InSingleRunMode();
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(1000);
                return;
            }
        restart:
            #region 开始前关所有吸嘴真空,但有可能是复吸，所以真空已经达到的不吸料，不关真空
            index = 0;
            foreach (var v in vac)
            {
                if (productStatus != null)
                {
                    if (productStatus[index] && vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                else
                {
                    if (vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                index++;
            }
            #endregion

            #region 下吸嘴和Z
            index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    //真空已经达到那个，就不用再下了
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut) && !vacSensor[index].WaitOn())
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                    index++;
                }
            }
            #endregion

            DateTime timeAfterNozzleAndZDown = DateTime.Now;
            if (!CheckFlowCondition()) return;
            #region 开真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        if (vacOther != null)
                            vacOther[i].Off();
                        if (!isDryRun)
                        {
                            vac[i].On();
                            if (revVacOther != null)
                                revVacOther[i].On();
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < vac.Count; i++)
                {
                    if (vacOther != null)
                        vacOther[i].Off();
                    if (!isDryRun)
                    {
                        vac[i].On();
                        if (revVacOther != null)
                            revVacOther[i].On();
                    }
                }
            }
            #endregion
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);

            #region 真空判断,若达不到，抬起吸嘴，没有断开真空
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in vacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            if (revVacOther != null)
                            {
                                foreach (var rv in revVacOther)
                                {
                                    rv.Off();
                                }
                            }
                            if (vacOther != null)
                            {
                                foreach (var v in vacOther)
                                {
                                    v.On();
                                }
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
            #endregion
            if (!CheckFlowCondition()) return;

            DateTime vacDelayAndSenseTime = DateTime.Now;

            #region 抬起吸嘴抬起Z
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            SingleAxisMove2Point(z, zSafePos);
            #endregion

            DateTime timeAfterNozzleUp = DateTime.Now;
            //真空检测前的延时
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;

            #region 抬起后的真空检测
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            if (revVacOther != null)
                            {
                                foreach (var rv in revVacOther)
                                {
                                    rv.Off();
                                }
                            }
                            if (vacOther != null)
                            {
                                foreach (var v in vacOther)
                                {
                                    v.On();
                                }
                            }
                            goto restart;
                        }
                    }
                }
            }
            #endregion

            #region 时间计算
            DateTime timeAfterVackCheck = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterNozzleAndZDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴下: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴下:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = vacDelayAndSenseTime - timeAfterNozzleAndZDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 达到真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 达到真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = timeAfterNozzleUp - vacDelayAndSenseTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴抬起: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴抬起:{ts3.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts4 = timeAfterVackCheck - timeAfterNozzleUp;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 抬起后真空检测时间: {ts4.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 抬起后真空检测时间:{ts4.Milliseconds}ms", MessageLevel.CT);
            #endregion

            InSingleRunMode();
        }
        public void NozzleGetProductExtWithChangeCylinder(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Cylinder> vacBreak,
                                        List<Sensor> vacSensor,
                                        List<Cylinder> vacOther,
                                        List<Cylinder> revVacOther,
                                        Cylinder changeCylinder,
                                        Cylinder vacOtherBreakCylinder,
                                        string zGetPos,
                                        string zSafePos,
                                        double zHeigth,
                                        double zSpeed,
                                        int vacBreakTime,
                                        int repeatCount,
                                        int nozzleTimeOut = 5000,
                                        int delayAfterOpenVac = 0,
                                        int delayBeforeVacCheck = 0,
                                        bool isDryRun = false,
                                        List<bool> productStatus = null,
                                        string alias = "")
        {
            InSingleRunMode();
            int index = 0;
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(1000);
                return;
            }
            List<int> countList = new List<int>();
            vacSensor.ForEach(o => countList.Add(repeatCount));
        restart:
            #region 开始前关所有吸嘴真空,但有可能是复吸，所以真空已经达到的不吸料，不关真空
            index = 0;
            foreach (var v in vac)
            {
                if (productStatus != null)
                {
                    if (productStatus[index] && vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                else
                {
                    if (vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                index++;
            }
            #endregion

            #region 下吸嘴和Z
            index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    //真空已经达到那个，就不用再下了
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleCylinderWait(changeCylinder, 1000, true);
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {

                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleCylinderWait(changeCylinder, 1000, true);
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut) && !vacSensor[index].WaitOn())
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                    index++;
                }
            }
            #endregion

            DateTime timeAfterNozzleAndZDown = DateTime.Now;
            if (!CheckFlowCondition()) return;
            #region 开真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        if (vacOther != null)
                            vacOther[i].Off();
                        if (!isDryRun)
                        {
                            vac[i].On();
                            if (revVacOther != null)
                                revVacOther[i].On();
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < vac.Count; i++)
                {
                    if (vacOther != null)
                        vacOther[i].Off();
                    if (!isDryRun)
                    {
                        vac[i].On();
                        if (revVacOther != null)
                            revVacOther[i].On();
                    }
                }
            }
            vacOtherBreakCylinder.On();
            #endregion
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);

            #region 真空判断,若达不到，抬起吸嘴，没有断开真空
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                countList[index]--;
                                if (countList[index] <= 0)
                                {
                                    //count = repeatCount;
                                    //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                    //抬起吸嘴
                                    vacOtherBreakCylinder.Off();
                                    vac[index].Off();
                                    vacBreak[index].On();
                                    Thread.Sleep(500);
                                    vacBreak[index].Off();
                                    foreach (var nozz in nozzle)
                                    {
                                        nozz.Off();
                                    }
                                    if (revVacOther != null)
                                    {
                                        foreach (var rv in revVacOther)
                                        {
                                            rv.Off();
                                        }
                                    }
                                    if (vacOther != null)
                                    {
                                        foreach (var v in vacOther)
                                        {
                                            v.On();
                                        }
                                    }
                                    ////出错，停下所有线程
                                    //_flowManager.Pause();
                                    ////若为报错，需重新检测启动信号
                                    //WaitForStart();
                                    //if (!CheckFlowCondition()) return;
                                    //goto restart;
                                }
                                else
                                {
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                    //抬起吸嘴
                                    vacOtherBreakCylinder.Off();
                                    vac[index].Off();
                                    vacBreak[index].On();
                                    Thread.Sleep(500);
                                    vacBreak[index].Off();
                                    foreach (var nozz in nozzle)
                                    {
                                        nozz.Off();
                                    }
                                    if (revVacOther != null)
                                    {
                                        foreach (var rv in revVacOther)
                                        {
                                            rv.Off();
                                        }
                                    }
                                    if (vacOther != null)
                                    {
                                        foreach (var v in vacOther)
                                        {
                                            v.On();
                                        }
                                    }
                                    Thread.Sleep(1000);
                                    goto restart;
                                }
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in vacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            countList[index]--;
                            if (countList[index] <= 0)
                            {
                                //count = repeatCount;
                                //MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                vacOtherBreakCylinder.Off();
                                vac[index].Off();
                                vacBreak[index].On();
                                Thread.Sleep(500);
                                vacBreak[index].Off();
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }

                                ////出错，停下所有线程
                                //_flowManager.Pause();
                                ////若为报错，需重新检测启动信号
                                //WaitForStart();
                                //if (!CheckFlowCondition()) return;
                                //goto restart;
                            }
                            else
                            {
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                vacOtherBreakCylinder.Off();
                                vac[index].Off();
                                vacBreak[index].On();
                                Thread.Sleep(500);
                                vacBreak[index].Off();
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                Thread.Sleep(1000);
                                goto restart;
                            }
                        }
                    }
                }
            }
            #endregion
            if (!CheckFlowCondition()) return;
            Task.Run(() =>
            {
                Thread.Sleep(vacBreakTime);
                vacOtherBreakCylinder.Off();
            });
            DateTime vacDelayAndSenseTime = DateTime.Now;

            #region Z先抬起一点
            double pos = z.Position - zHeigth;
            SingleAxisMove2PointSetSpeed(z, pos, zSpeed);
            #endregion

            #region 抬起吸嘴抬起Z
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //Task task1 = Task.Run(async () =>
            // {
            //     await Task.Delay(150);
            //     changeCylinder.Off();
            // });
            SingleAxisMove2Point(z, zSafePos);
            #endregion

            DateTime timeAfterNozzleUp = DateTime.Now;
            //真空检测前的延时
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;

            #region 抬起后的真空检测
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {
                                countList[index]--;
                                if (countList[index] <= 0)
                                {
                                    countList[index] = repeatCount;
                                    Thread.Sleep(500);
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                    //出错，停下所有线程
                                    //Task.WaitAll(task1);
                                    _flowManager.Pause();
                                    if (revVacOther != null)
                                    {
                                        foreach (var rv in revVacOther)
                                        {
                                            rv.Off();
                                        }
                                    }
                                    if (vacOther != null)
                                    {
                                        foreach (var v in vacOther)
                                        {
                                            v.On();
                                        }
                                    }
                                    if (!CheckFlowCondition()) return;
                                    SingleCylinderOperate(changeCylinder, 5000, true);
                                    if (!CheckFlowCondition()) return;
                                    goto restart;
                                }
                                else
                                {
                                    Thread.Sleep(500);
                                    //Task.WaitAll(task1);
                                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                    if (revVacOther != null)
                                    {
                                        foreach (var rv in revVacOther)
                                        {
                                            rv.Off();
                                        }
                                    }
                                    if (vacOther != null)
                                    {
                                        foreach (var v in vacOther)
                                        {
                                            v.On();
                                        }
                                    }
                                    Thread.Sleep(500);
                                    if (!CheckFlowCondition()) return;
                                    SingleCylinderOperate(changeCylinder, 5000, true);
                                    if (!CheckFlowCondition()) return;
                                    goto restart;
                                }
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            countList[index]--;
                            if (countList[index] <= 0)
                            {
                                countList[index] = repeatCount;
                                Thread.Sleep(500);
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                //Task.WaitAll(task1);
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                SingleCylinderOperate(changeCylinder, 5000, true);
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                            else
                            {
                                Thread.Sleep(500);
                                //Task.WaitAll(task1);
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                if (!CheckFlowCondition()) return;
                                if (revVacOther != null)
                                {
                                    foreach (var rv in revVacOther)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                SingleCylinderOperate(changeCylinder, 5000, true);
                                if (!CheckFlowCondition()) return;
                                goto restart;

                            }
                        }
                    }
                }
            }
            #endregion

            #region 时间计算
            DateTime timeAfterVackCheck = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterNozzleAndZDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴下: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴下:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = vacDelayAndSenseTime - timeAfterNozzleAndZDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 达到真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 达到真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = timeAfterNozzleUp - vacDelayAndSenseTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴抬起: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴抬起:{ts3.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts4 = timeAfterVackCheck - timeAfterNozzleUp;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 抬起后真空检测时间: {ts4.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 抬起后真空检测时间:{ts4.Milliseconds}ms", MessageLevel.CT);
            #endregion
            //Task.WaitAll(task1);
            InSingleRunMode();
        }
        public void NozzleGetProductExtDoE(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Sensor> vacSensor,
                                        List<Cylinder> vacOther,
                                        List<Cylinder> position,
                                        Cylinder checkChangeCylinder,
                                        string zGetPos,
                                        string zSafePos,
                                        string localName,
                                        int nozzleTimeOut = 5000,
                                        int delayAfterOpenVac = 0,
                                        int delayBeforeVacCheck = 0,
                                        bool isDryRun = false,
                                        List<bool> productStatus = null,
                                        string alias = "",
                                        int releaseTimeAfter = 0,
                                        int releaseTimeBefore = 0)
        {
            int index = 0;

            InSingleRunMode();
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(1000);
                return;
            }
        restart:
            #region 开始前关所有吸嘴真空,但有可能是复吸，所以真空已经达到的不吸料，不关真空
            index = 0;
            foreach (var v in vac)
            {
                if (productStatus != null)
                {
                    if (productStatus[index] && vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                else
                {
                    if (vacSensor[index].WaitOn())
                        v.On();
                    else
                        v.Off();
                }
                index++;
            }
            #endregion

            #region 下吸嘴和Z
            index = 0;
            if (productStatus != null)
            {
                foreach (var nozz in nozzle)
                {
                    //真空已经达到那个，就不用再下了
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index] && !vacSensor[index].WaitOn())
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!vacSensor[index].WaitOn())
                        nozz.On();
                    index++;
                }
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2Point(z, zGetPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut) && !vacSensor[index].WaitOn())
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                    index++;
                }
            }
            #endregion

            DateTime timeAfterNozzleAndZDown = DateTime.Now;
            if (!CheckFlowCondition()) return;
            #region 开真空
            if (productStatus != null)
            {
                for (int i = 0; i < productStatus.Count; i++)
                {
                    if (productStatus[i])
                    {
                        if (vacOther != null)
                            vacOther[i].Off();
                        if (!isDryRun)
                        {
                            vac[i].On();
                        }
                        if (position != null)
                        {
                            Thread.Sleep(releaseTimeBefore);
                            SingleCylinderOperate(position[0], 5000, false);
                            Thread.Sleep(releaseTimeAfter);
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < vac.Count; i++)
                {
                    if (vacOther != null)
                        vacOther[i].Off();
                    if (!isDryRun)
                    {
                        vac[i].On();
                    }
                    if (position != null)
                    {
                        Thread.Sleep(releaseTimeBefore);
                        SingleCylinderOperate(position[0], 5000, false);
                        Thread.Sleep(releaseTimeAfter);
                    }
                }
            }
            #endregion
            //开真空后延时
            System.Threading.Thread.Sleep(delayAfterOpenVac);

            #region 真空判断,若达不到，抬起吸嘴，没有断开真空
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            //若感应到真空，说明有产品
                            if (!vs.WaitOn())
                            {
                                if (position != null)
                                {
                                    SingleCylinderOperate(position[0], 5000, true);
                                    Thread.Sleep(200);
                                }
                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                                //抬起吸嘴
                                foreach (var nozz in nozzle)
                                {
                                    nozz.Off();
                                }
                                if (position != null)
                                {
                                    foreach (var rv in position)
                                    {
                                        rv.Off();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                if (position != null)
                                {
                                    Thread.Sleep(500);
                                    SingleCylinderOperate(position[0], 5000, false);
                                }
                                //出错，停下所有线程
                                _flowManager.Pause();
                                //若为报错，需重新检测启动信号
                                WaitForStart();
                                if (!CheckFlowCondition()) return;
                                if (position != null)
                                {
                                    SingleCylinderOperate(position[0], 5000, true);
                                    Thread.Sleep(200);
                                }
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    foreach (var vs in vacSensor)
                    {
                        //若感应到真空，说明有产品
                        if (!vs.WaitOn())
                        {
                            if (position != null)
                            {
                                SingleCylinderOperate(position[0], 5000, true);
                                Thread.Sleep(200);
                            }
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到产品,请检查是否有产品", this.Description, 6, vs.Module));
                            //抬起吸嘴
                            foreach (var nozz in nozzle)
                            {
                                nozz.Off();
                            }
                            if (position != null)
                            {
                                foreach (var rv in position)
                                {
                                    rv.Off();
                                }
                            }
                            if (vacOther != null)
                            {
                                foreach (var v in vacOther)
                                {
                                    v.On();
                                }
                            }
                            if (position != null)
                            {
                                Thread.Sleep(500);
                                SingleCylinderOperate(position[0], 5000, false);
                            }
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            if (position != null)
                            {
                                SingleCylinderOperate(position[0], 5000, true);
                                Thread.Sleep(200);
                            }
                            goto restart;
                        }
                    }
                }
            }
            #endregion
            if (!CheckFlowCondition()) return;

            DateTime vacDelayAndSenseTime = DateTime.Now;

            #region 抬起吸嘴抬起Z
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            SingleCylinderWait(checkChangeCylinder, 1000, false);
            SingleAxisMove2Point(z, zSafePos);
            #endregion

            DateTime timeAfterNozzleUp = DateTime.Now;
            //真空检测前的延时
            Thread.Sleep(delayBeforeVacCheck);
            if (!CheckFlowCondition()) return;

            #region 抬起后的真空检测
            if (!isDryRun)
            {
                if (productStatus != null)
                {
                    index = 0;
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (productStatus[index])
                        {
                            if (!vs.WaitOn())
                            {

                                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                                //出错，停下所有线程
                                _flowManager.Pause();
                                if (position != null)
                                {
                                    foreach (var rv in position)
                                    {
                                        rv.On();
                                    }
                                }
                                if (vacOther != null)
                                {
                                    foreach (var v in vacOther)
                                    {
                                        v.On();
                                    }
                                }
                                Thread.Sleep(500);
                                if (!CheckFlowCondition()) return;
                                goto restart;
                            }
                        }
                        index++;
                    }
                }
                else
                {
                    //抬起后未感应到真空
                    foreach (var vs in vacSensor)
                    {
                        if (!vs.WaitOn())
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{localName}真空{vs.Description}未感应到,吸料失败!", this.Description, 6, vs.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            if (position != null)
                            {
                                foreach (var rv in position)
                                {
                                    rv.On();
                                }
                            }
                            if (vacOther != null)
                            {
                                foreach (var v in vacOther)
                                {
                                    v.On();
                                }
                            }
                            Thread.Sleep(500);
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                }
            }
            #endregion

            #region 时间计算
            DateTime timeAfterVackCheck = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterNozzleAndZDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴下: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴下:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = vacDelayAndSenseTime - timeAfterNozzleAndZDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 达到真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 达到真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = timeAfterNozzleUp - vacDelayAndSenseTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} Z&吸嘴抬起: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 Z&吸嘴抬起:{ts3.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts4 = timeAfterVackCheck - timeAfterNozzleUp;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 抬起后真空检测时间: {ts4.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴取料 抬起后真空检测时间:{ts4.Milliseconds}ms", MessageLevel.CT);
            #endregion

            InSingleRunMode();
        }
        public void NozzlePutProductExt(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Cylinder> revVac,
                                        List<Cylinder> vacOther,
                                        string zPutPos,
                                        string zSafePos,
                                        double zRelPos,
                                        double zRelSpeed,
                                        int nozzleTimeOut = 5000,
                                        int delayBeforeNozzleUp = 0,
                                        List<bool> productStatus = null,
                                        string alias = "")
        {

            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));

            #region 下吸嘴和Z
            int index = 0;
            if (productStatus != null)
            {
                double value = z.MotionPosition[zPutPos] - zRelPos;
                bool isCheckFlag = true;
                //Task.Run(() =>
                //{
                //    while (isCheckFlag)
                //    {
                //        if (z.Position >= value)
                //        {
                //            SingleAxisChangeSpeed(z, zRelSpeed);
                //            break;
                //        }
                //        Thread.Sleep(2);
                //    }
                //});
                SingleAxisMove2Point(z, zPutPos);
                isCheckFlag = false;
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"Z运动结束", this.Description, 1, nozzle[0].Module));
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                double value = z.MotionPosition[zPutPos] - zRelPos;
                bool isCheckFlag = true;
                //Task.Run(() =>
                //{
                //    while (isCheckFlag)
                //    {
                //        if (z.Position >= value)
                //        {
                //            SingleAxisChangeSpeed(z, zRelSpeed);
                //            break;
                //        }
                //        Thread.Sleep(2);
                //    }
                //});
                SingleAxisMove2Point(z, zPutPos);
                isCheckFlag = false;
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"Z运动结束", this.Description, 1, nozzle[0].Module));
                if (!CheckFlowCondition()) return;
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            #endregion

            DateTime timeAfterZNozzleDown = DateTime.Now;
            if (!CheckFlowCondition()) return;

            #region 关真空开破真空
            if (productStatus != null)
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        if (productStatus[index])
                            v.On();
                        index++;
                    }
                }
                index = 0;
                foreach (var rv in vac)
                {
                    if (productStatus[index])
                        rv.Off();
                    index++;
                }
            }
            else
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        v.On();
                        index++;
                    }
                }
                //关真空
                foreach (var rv in vac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in revVac)
                {
                    if (productStatus[index])
                        rv.On();
                    index++;
                }
            }
            else
            {
                //开破真空
                foreach (var rv in revVac)
                {
                    rv.On();
                }
            }
            #endregion

            if (!CheckFlowCondition()) return;
            DateTime cloaseVacTime = DateTime.Now;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);

            #region 抬吸嘴和Z
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            SingleAxisMove2Point(z, zSafePos);
            if (!CheckFlowCondition()) return;
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            #endregion

            #region 关破真空
            foreach (var rv in revVac)
            {
                rv.Off();
            }
            //若为报错，需重新检测启动信号
            if (!CheckFlowCondition()) return;
            #endregion

            #region 时间纪录
            DateTime nozzleAndZUpTime = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterZNozzleDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z下降时间: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z下降时间:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = cloaseVacTime - timeAfterZNozzleDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 关真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 关真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = nozzleAndZUpTime - cloaseVacTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z抬起时间: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z抬起时间:{ts3.Milliseconds}ms", MessageLevel.CT);
            #endregion
        }
        public void NozzlePutProductExt(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Cylinder> revVac,
                                        List<Cylinder> vacOther,
                                        string zPutPos,
                                        double zSafePos,
                                        int nozzleTimeOut = 5000,
                                        int delayBeforeNozzleUp = 0,
                                        List<bool> productStatus = null,
                                        string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                SingleAxisMove2Point(z, zPutPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                SingleAxisMove2Point(z, zPutPos);
                if (!CheckFlowCondition()) return;
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            DateTime timeAfterZNozzleDown = DateTime.Now;
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空
            if (productStatus != null)
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        if (productStatus[index])
                            v.On();
                        index++;
                    }
                }
                index = 0;
                foreach (var rv in vac)
                {
                    if (productStatus[index])
                        rv.Off();
                    index++;
                }
            }
            else
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        v.On();
                        index++;
                    }
                }
                //关真空
                foreach (var rv in vac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in revVac)
                {
                    if (productStatus[index])
                        rv.On();
                    index++;
                }
            }
            else
            {
                //开破真空
                foreach (var rv in revVac)
                {
                    rv.On();
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            DateTime cloaseVacTime = DateTime.Now;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            SingleAxisMove2Point(z, zSafePos);
            if (!CheckFlowCondition()) return;
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //关破真空
            foreach (var rv in revVac)
            {
                rv.Off();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            DateTime nozzleAndZUpTime = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterZNozzleDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z下降时间: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z下降时间:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = cloaseVacTime - timeAfterZNozzleDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 关真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 关真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = nozzleAndZUpTime - cloaseVacTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z抬起时间: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z抬起时间:{ts3.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProductExtDoE(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Cylinder> revVac,
                                        List<Cylinder> vacOther,
                                        Axis x,
                                        Axis y,
                                        string xyPos,
                                        string zPutPos,
                                        double zSafePos,
                                        int nozzleTimeOut = 5000,
                                        int delayBeforeNozzleUp = 0,
                                        List<bool> productStatus = null,
                                        string alias = "")
        {
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak())
                return;
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                SingleAxisMove2Point(z, zPutPos);
                if (!CheckFlowCondition()) return;
                //动xy到目标位置
                AxisMoveSimultaneously(x, y, xyPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
            }
            else
            {
                SingleAxisMove2Point(z, zPutPos);
                if (!CheckFlowCondition()) return;
                //动xy到目标位置
                AxisMoveSimultaneously(x, y, xyPos);
                if (!CheckFlowCondition()) return;
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
            }
            DateTime timeAfterZNozzleDown = DateTime.Now;
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空
            if (productStatus != null)
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        if (productStatus[index])
                            v.On();
                        index++;
                    }
                }
                index = 0;
                foreach (var rv in vac)
                {
                    if (productStatus[index])
                        rv.Off();
                    index++;
                }
            }
            else
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        v.On();
                        index++;
                    }
                }
                //关真空
                foreach (var rv in vac)
                {
                    rv.Off();
                }
            }
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in revVac)
                {
                    if (productStatus[index])
                        rv.On();
                    index++;
                }
            }
            else
            {
                //开破真空
                foreach (var rv in revVac)
                {
                    rv.On();
                }
            }
            WaitForStart();
            if (!CheckFlowCondition()) return;
            DateTime cloaseVacTime = DateTime.Now;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            SingleAxisMove2Point(z, zSafePos);
            if (!CheckFlowCondition()) return;
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //关破真空
            foreach (var rv in revVac)
            {
                rv.Off();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            DateTime nozzleAndZUpTime = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterZNozzleDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z下降时间: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z下降时间:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = cloaseVacTime - timeAfterZNozzleDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 关真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 关真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = nozzleAndZUpTime - cloaseVacTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z抬起时间: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z抬起时间:{ts3.Milliseconds}ms", MessageLevel.CT);
        }
        public void NozzlePutProductExtDoE2(Axis z,
                                        List<Cylinder> nozzle,
                                        List<Cylinder> vac,
                                        List<Cylinder> revVac,
                                        List<Cylinder> vacOther,
                                        Cylinder position,
                                        Cylinder checkChangeCylinder,
                                        Axis x,
                                        Axis y,
                                        string xyPos,
                                        string zPutPos,
                                        double zSafePos,
                                        double zPutRelPos,
                                        double zPutRelPosSpeed,
                                        int nozzleTimeOut = 5000,
                                        int delayBeforeNozzleUp = 0,
                                        List<bool> productStatus = null,
                                        string alias = "",
                                        int clampDelayCylinderAfter = 0,
                                        int clampDelayCylinderBefore = 0,
                                        int headerIndex = 0)
        {

            InSingleRunMode();
            DateTime dateTime = DateTime.Now;
            if (isSimulate)
            {
                Thread.Sleep(500);
                return;
            }
        restart:
            if (IsBreak()) return;
            //确保定位松开
            SingleCylinderOperate(position, 5000, false);
            List<string> nozzleNames = new List<string>();
            nozzle.ForEach(a => nozzleNames.Add(a.Description));
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Log, $"多吸嘴:{string.Join(",", nozzleNames)}放料", this.Description, 0, nozzle[0].Module));
            int index = 0;
            if (productStatus != null)
            {
                CTMoveStartCalculateNode();
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2Point(z, z.MotionPosition[zPutPos] - zPutRelPos);
                if (!CheckFlowCondition()) return;
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2PointSetSpeed(z, z.MotionPosition[zPutPos], zPutRelPosSpeed);
                if (!CheckFlowCondition()) return;
                //动xy到目标位置
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                AxisMoveSimultaneously(x, y, xyPos);
                if (!CheckFlowCondition()) return;
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                        nozz.On();
                    index++;
                }
                index = 0;
                foreach (var nozz in nozzle)
                {
                    if (productStatus[index])
                    {
                        if (!nozz.WaitOn(nozzleTimeOut))
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                            //出错，停下所有线程
                            _flowManager.Pause();
                            //若为报错，需重新检测启动信号
                            WaitForStart();
                            if (!CheckFlowCondition()) return;
                            goto restart;
                        }
                    }
                    index++;
                }
                CTMoveEndCalculateNode(out double time1);
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.CT, time1.ToString("0.0"), "", 0, $"Arm{headerIndex + 1}治具到精定位"));
            }
            else
            {
                CTMoveStartCalculateNode();
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2Point(z, z.MotionPosition[zPutPos] - zPutRelPos);
                if (!CheckFlowCondition()) return;
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                SingleAxisMove2PointSetSpeed(z, z.MotionPosition[zPutPos], zPutRelPosSpeed);
                if (!CheckFlowCondition()) return;
                //动xy到目标位置
                SingleCylinderWait(checkChangeCylinder, 1000, false);
                AxisMoveSimultaneously(x, y, xyPos);
                if (!CheckFlowCondition()) return;
                foreach (var nozz in nozzle)
                {
                    nozz.On();
                }
                foreach (var nozz in nozzle)
                {
                    if (!nozz.WaitOn(nozzleTimeOut))
                    {
                        MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到动点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                        //出错，停下所有线程
                        _flowManager.Pause();
                        //若为报错，需重新检测启动信号
                        WaitForStart();
                        if (!CheckFlowCondition()) return;
                        goto restart;
                    }
                }
                CTMoveEndCalculateNode(out double time1);
                MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.CT, time1.ToString("0.0"), "", 0, $"Arm{headerIndex + 1}治具到精定位"));

            }
            DateTime timeAfterZNozzleDown = DateTime.Now;
            CTMoveStartCalculateNode();
            WaitForStart();
            if (!CheckFlowCondition()) return;
            //关真空
            if (productStatus != null)
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        if (productStatus[index])
                            v.On();
                        index++;
                    }
                }
                index = 0;
                foreach (var rv in vac)
                {
                    if (productStatus[index])
                        rv.Off();
                    index++;
                }
            }
            else
            {
                if (vacOther != null)
                {
                    index = 0;
                    foreach (var v in vacOther)
                    {
                        v.On();
                        index++;
                    }
                }
                //关真空
                foreach (var rv in vac)
                {
                    rv.Off();
                }
            }
            Thread.Sleep(500);
            if (!CheckFlowCondition()) return;
            if (productStatus != null)
            {
                index = 0;
                foreach (var rv in revVac)
                {
                    if (productStatus[index])
                        rv.On();
                    index++;
                }
            }
            else
            {
                //开破真空
                foreach (var rv in revVac)
                {
                    rv.On();
                }
            }
            //定位夹紧
            Thread.Sleep(clampDelayCylinderBefore);
            SingleCylinderOperate(position, 5000, true);
            Thread.Sleep(clampDelayCylinderAfter);
            WaitForStart();
            if (!CheckFlowCondition()) return;
            DateTime cloaseVacTime = DateTime.Now;
            //抬吸嘴前的延时
            System.Threading.Thread.Sleep(delayBeforeNozzleUp);
            foreach (var nozz in nozzle)
            {
                nozz.Off();
            }
            SingleCylinderWait(checkChangeCylinder, 1000, false);
            SingleAxisMove2Point(z, zSafePos);
            if (!CheckFlowCondition()) return;
            foreach (var nozz in nozzle)
            {
                if (!nozz.WaitOff(nozzleTimeOut))
                {
                    MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Warn, $"{nozz.Description}到原点{string.Join(",", nozz.MoveNames)}超时", this.Description, 1, nozz.Module));
                    //出错，停下所有线程
                    _flowManager.Pause();
                }
            }
            //关破真空
            foreach (var rv in revVac)
            {
                rv.Off();
            }
            //若为报错，需重新检测启动信号
            WaitForStart();
            if (!CheckFlowCondition()) return;

            DateTime nozzleAndZUpTime = DateTime.Now;

            TimeSpan ts = DateTime.Now - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 总时间: {ts.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 总时间:{ts.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts1 = timeAfterZNozzleDown - dateTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z下降时间: {ts1.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z下降时间:{ts1.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts2 = cloaseVacTime - timeAfterZNozzleDown;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 关真空时间: {ts2.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 关真空时间:{ts2.Milliseconds}ms", MessageLevel.CT);

            TimeSpan ts3 = nozzleAndZUpTime - cloaseVacTime;
            if (!string.IsNullOrEmpty(alias))
                LogHelper.Instance.Log(this.Description, $"{alias} 吸嘴&Z抬起时间: {ts3.Milliseconds}ms", MessageLevel.CT);
            else
                LogHelper.Instance.Log(this.Description, $"多吸嘴放料 {string.Join(",", nozzle.Select(n => n.Description).ToArray())} 吸嘴&Z抬起时间:{ts3.Milliseconds}ms", MessageLevel.CT);
            CTMoveEndCalculateNode(out double time);
            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.CT, time.ToString("0.0"), "", 0, $"Arm{headerIndex + 1}放料精定位"));

            InSingleRunMode();
        }
    }
    public enum FlowMode
    {
        Home,
        Auto,
        Calibrate,
        SpotCheck,
    }
}
